//
//  BBUnderlayView.m
//  xNose
//
//  Created by ben smith on 14/09/08.
//  Copyright 2008 __MyCompanyName__. All rights reserved.
//

#import "BBUnderlayView.h"
#import "BBNodeController.h"
#import "BBControllerNodeView.h"
#import "BBNodeViewFactory.h"
#import "BBViewThumbnailer.h"
#import "BBContainerInfoNodeView.h"
#import "BBLibraryNodeView.h"
#import "BBLibraryView.h"
#import "BBLibraryController.h"
#import "BBNode.h"
#import "BBGrandTotalView.h"
#import "BBRootNodeView.h"
#import "BBAppController.h"
#import "BBOverlayView.h"

@implementation BBUnderlayView
@synthesize dragImageView;
@synthesize pinImageView;
@synthesize dragNode;

- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code here.
			startDrag = YES;
			singleTouch = NO;
			self.dragNode = nil;
			vertPin = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"pinVertical" ofType:@"png"]];
			horizPin = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"pinHoriz" ofType:@"png"]];
    }
    return self;
}

- (void)drawRect:(NSRect)rect {
    // Drawing code here.
}

-(void)initializeDrag
{
	NSView * hitview = [[BBNodeController sharedNodeController] hitTest:mouseDown];
	if ([hitview isKindOfClass:[BBGrandTotalView class]]) return;
	if ([hitview isKindOfClass:[BBRootNodeView class]]) return;
	self.dragNode = [(BBNodeView*)hitview node];
	needsAdding = NO;
	if (self.dragNode == nil) return;
	hit = [hitview frame];
	NSImage * dragImage;
	
	if ([hitview isKindOfClass:[BBLibraryNodeView class]]) {
		// check to see that we are in the view and not in the handle
		needsAdding = YES;
		dragImage = [(BBLibraryNodeView*)hitview viewImage];
		smallImageRect.size = [dragImage size];
	} else {
		if ([self.dragNode isContainer]) {
			dragImage =  [BBViewThumbnailer createImageFromSubView:[hitview superview] rect:hit];			
		} else {
			dragImage =  [BBViewThumbnailer createImageFromView:hitview];
		}		
		smallImageRect = hit;
	}

	smallImageRect.size.height /= 1.5;
	smallImageRect.size.width /= 1.5;
	
	smallImageRect.origin.x = mouseDown.x - (NSWidth(smallImageRect)/2.0);
	smallImageRect.origin.y = mouseDown.y - (NSHeight(smallImageRect)/2.0);
	NSImageView * iView = [[NSImageView alloc] initWithFrame:smallImageRect];
	
	[iView setImageFrameStyle:NSImageFrameNone];
	[iView setImageScaling:NSScaleToFit];
	[iView setImage:dragImage];
	[iView setEditable:NO];
	[self addSubview:iView];
	self.dragImageView = iView;
	[iView release];

	startDrag = NO;
	
	[self setNeedsDisplay:YES];
}

-(void)setPinImage:(NSEvent*)theEvent
{
	if (pinImageView == nil) {
		NSSize iSize = [vertPin size];
		pinImageView = [[NSImageView alloc] initWithFrame:NSMakeRect(0, 0, iSize.width, iSize.height)];
		
		[pinImageView setImageFrameStyle:NSImageFrameNone];
		[pinImageView setImageScaling:NSScaleToFit];
		[pinImageView setImage:vertPin];		
	}
	BBNodeView * hitview = (BBNodeView *)[[BBNodeController sharedNodeController] hitTest:mouseDown forNode:self.dragNode];
	if (hitview == nil) {
		[pinImageView removeFromSuperview];
		//[[NSCursor disappearingItemCursor] set]; 
	} else {
//		[[NSCursor arrowCursor] set]; 
		if ([pinImageView superview] == nil) [self addSubview:pinImageView];
		NSRect pinFrame;
		if ([dragNode isContainer]) {
			NSSize iSize = [vertPin size];
			pinFrame = NSMakeRect(0, 0, iSize.width, iSize.height);
			[pinImageView setImage:vertPin];
			pinFrame.origin.y = NSMaxY([hitview frame]);
			if (mouseDown.x < NSMidX([hitview frame])) {
				above = YES;
				pinFrame.origin.x = NSMinX([hitview frame]) - NSWidth(pinFrame);
			} else {
				above = NO;
				pinFrame.origin.x = NSMaxX([hitview frame]);
			}			
		} else {
			NSSize iSize = [horizPin size];
			pinFrame = NSMakeRect(0, 0, iSize.width, iSize.height);
			[pinImageView setImage:horizPin];
			pinFrame.origin.x = NSMinX([hitview frame]);
			if (mouseDown.y < NSMidY([hitview frame])) {
				above = NO;
				pinFrame.origin.y = NSMinY([hitview frame]) - (NSHeight(pinFrame)/2.0);
				// does this node have kids? if so i really need to put it under them
				// if it is open
				if ([hitview.node hasChildren] && [hitview.node isOpen]) {
					NSView * lastKid = [[hitview.node.children lastObject] view];
					pinFrame.origin.y = NSMinY([lastKid frame]) - (NSHeight(pinFrame)/2.0);					
				}
			} else {
				above = YES;
				pinFrame.origin.y = NSMaxY([hitview frame]) - (NSHeight(pinFrame)/2.0);
			}
		}
		[pinImageView setFrame:pinFrame];
	}		
}

-(void)mouseDown:(NSEvent*)theEvent
{
	mouseDown = [[[self window] contentView] convertPoint:[theEvent locationInWindow] toView:self];	
}

-(void)mouseDragged:(NSEvent*)theEvent
{
	NSPoint oldMouse = mouseDown;
	mouseDown = [[[self window] contentView] convertPoint:[theEvent locationInWindow] toView:self];

	// check to see if we are in single touch and are on top of something that we should not be 
	// dragging
	if (singleTouch) {
		NSView * hitview = [[BBNodeController sharedNodeController] hitTest:mouseDown];
		if (hitview != nil) return;		
	}
	
	
	// first check to see if we just came into the drag, if so set it up
	if (startDrag && !isShifting) {
		// then we need to start the drag process
		[self setPinImage:theEvent];
		[self initializeDrag];
		if (!startDrag) return;
	}
	
	// otherwise check to see if we are scrolling the view around
	if (isShifting || (self.dragNode == nil)) {
		isShifting = YES;
		float deltaX = mouseDown.x - oldMouse.x; // need to do this because the TUIO events do not have a delta x/y
		float deltaY = mouseDown.y - oldMouse.y; // need to do this because the TUIO events do not have a delta x/y
		[[BBNodeController sharedNodeController] scrollAllNodesX:deltaX y:deltaY animate:NO];
		return;
	}
	
	// here we are in a drag event so update the drag image
	[[BBNodeController sharedNodeController] setActive:YES];
	[[[BBNodeController sharedNodeController] blobDrawView] setDrawTrash:YES];
	
	NSRect f = [self.dragImageView frame];
	
	f.origin.x = mouseDown.x - (NSWidth(f)/2.0);
	f.origin.y = mouseDown.y - (NSHeight(f)/2.0);
	
	[self.dragImageView setFrame:f];
	[self setPinImage:theEvent];
	[self setNeedsDisplay:YES];
}


-(void)otherMouseUp:(NSEvent*)theEvent
{
	singleTouch = NO;
	[self mouseUp:theEvent];
}

-(void)otherMouseDragged:(NSEvent*)theEvent
{
	NSPoint thisMouseDown = [[[self window] contentView] convertPoint:[theEvent locationInWindow] toView:self];	
	if ((fabs(thisMouseDown.x - mouseDown.x) > 8) || (fabs(thisMouseDown.y - mouseDown.y) > 8))
		touchDidDrag = YES;
	[self mouseDragged:theEvent];
}

-(void)otherMouseDown:(NSEvent*)theEvent
{
	[self mouseDown:theEvent];
	singleTouch = YES;
	touchDidDrag = NO;
	[self startTimingTouchDrag:theEvent];
}


-(void)startTimingTouchDrag:(NSEvent*)theEvent
{
	// time how long the touch is on our view
	// if it is still here adter the clock runs out then we strt a drag
	[self performSelector:@selector(clockRanOut:) withObject:theEvent afterDelay:0.5];
}

-(void)clockRanOut:(NSEvent*)theEvent
{
	if (!singleTouch) return;
	if (touchDidDrag) return;

	if (singleTouch) singleTouch = NO;

	if (startDrag && !isShifting) {
		// then we need to start the drag process
		[self setPinImage:theEvent];
		[self initializeDrag];
		if (!startDrag) return;
	}
}

-(void)mouseUp:(NSEvent*)theEvent
{
	isShifting  = NO;
	if (startDrag) return;
	startDrag = YES;
	[self.dragImageView removeFromSuperview];
	[self.pinImageView removeFromSuperview];
	[[[BBNodeController sharedNodeController] blobDrawView] setDrawTrash:NO];
	[[BBNodeController sharedNodeController] setActive:NO];

	mouseDown = [[[self window] contentView] convertPoint:[theEvent locationInWindow] toView:self];
	// first check to see if we hit the library
	if ([[BBLibraryController sharedLibraryController] pointInLibrary:mouseDown]) {
		// then add this to the library
		[[BBLibraryController sharedLibraryController] addNode:self.dragNode];
		[self setNeedsDisplay:YES];
		return;
	}
	
	[[NSNotificationCenter defaultCenter] postNotificationName:@"BBCloseLibraryNotification" object:self];
	
	BBNodeView * hitview = (BBNodeView *)[[BBNodeController sharedNodeController] hitTest:mouseDown forNode:self.dragNode];
	if ((hitview == nil) || ([hitview isKindOfClass:[BBRootNodeView class]])) {
		if (needsAdding && [dragNode isContainer]) {
			// add it to the end of the root containers
			dragNode.position = mouseDown;
			BBNode * after = [[[BBNodeController sharedNodeController] rootNode].children lastObject];
			[[BBNodeController sharedNodeController] addNode:[self.dragNode deepCopy] nextTo:after above:NO];			
			[self setNeedsDisplay:YES];
			self.dragNode = nil;
			return;
		}
		// then poof it if it is in the trash rect
		if (NSPointInRect(mouseDown, [[BBNodeController sharedNodeController] trashRect])) {
			NSPoint converted = [[self window] convertBaseToScreen:mouseDown];// toView:self];
			NSShowAnimationEffect(NSAnimationEffectPoof,converted , NSZeroSize, nil, nil, nil);
			[[BBNodeController sharedNodeController] removeNode:self.dragNode];	
			[self setNeedsDisplay:YES];
			self.dragNode = nil;
			return;			
		} else {
			// just ignore it
			self.dragNode = nil;
			[self setNeedsDisplay:YES];
		}
	}

	
	if (needsAdding) {
		[[BBNodeController sharedNodeController] addNode:[self.dragNode deepCopy] nextTo:hitview.node above:above] ;			
	} else {
		[[BBNodeController sharedNodeController] moveNode:self.dragNode nextTo:hitview.node above:above] ;	
	}
	
	self.dragNode = nil;
	[self setNeedsDisplay:YES];
}


@end
